Skip to content

AdmittanceTransforms 的六个位姿:导纳定律的坐标桥梁 ​

ros2_controllers(Humble,commit 2105376)的 admittance_controller 里有个容易被一眼扫过的结构体 AdmittanceTransforms(admittance_rule.hpp:43-61):它缓存一个控制周期需要的 6 个位姿,由 get_all_transforms(admittance_rule_impl.hpp:142-167)调 6 次 kinematics_->calculate_link_transform() 填满——第 1 次用参考关节角,后 5 次用当前关节角。为什么恰好是这六个、各自被谁消费?这六个位姿是理解导纳定律坐标系关系的钥匙:力在 sensor frame 测得、重力只在 world frame 是常向量、M/D/K 定义在 control frame、弹簧零点在参考轨迹上,把它们搬进 base frame 全靠这六座桥。文中行号对应锚点 commit 的源码。控制器整体架构见本站《ros2_control 控制器架构与 chainable 机制》。

六个位姿与消费点 ​

导纳定律在 base frame 计算:X_ddot = M⁻¹(F_base − D·X_dot − K·X)(impl:290-292)。定律的输入分别诞生在别的 frame,六个位姿就是搬运工:

成员 含义 关节角 消费点 用哪部分
ref_base_ft_ 传感器在参考构型下的位姿 参考(:147) :202 存入 state → :261-265 算 X 的零点 平移+旋转
base_ft_ 传感器当前位姿 当前(:152) :187 组 R_world_sensor 仅旋转
world_base_ base 在 world 下的位姿 当前(:156) :187 / :189 / :194-196 三次 仅旋转
base_cog_ 工具质心当前位姿 当前(:159) :189 重力力矩杠杆臂 仅旋转(配 cog_pos_ 参数)
base_control_ control frame 当前位姿 当前(:162) :200 → K/D 共轭旋转(:238/:252)、轴掩码往返(:282-288) 仅旋转
base_tip_ 末端当前位姿 当前(:154) 无(:155 写入后全包零读取) —

参考 vs 当前:两份关节角,两个世界 ​

  • 参考世界:第①拍 read_state_reference_interfaces(admittance_controller.cpp:447)读 reference interfaces。这组接口有两个写入者——级联时 JTC 直接写;独立运行时话题经 RealtimeBuffer 由 update_reference_from_subscribers(:402-430)写入。基类 update() 先调话题消费再调 update_and_write_commands(chainable_controller_interface.cpp:35→42)。
  • 当前世界:第②拍 read_state_from_hardware(:450)读 hardware state interfaces(编码器)。
  • 对应工业控制器的设定点 vs 编码器反馈;定律里的 X 是跟随误差的笛卡尔版本。
  • 六个位姿里只有 ref_base_ft_ 住在参考世界——弹簧零点需要「上游要你去哪」。其余五个全是当前构型:力怎么旋转、重力怎么减、参数怎么换系只取决于臂的真实姿态。用参考姿态旋转力读数会在臂滞后于指令时出错,而臂滞后最大的时刻恰是接触加载、力读数最重要的时刻。
  • 实测关节角 ≈ 上周期指令(参考 + 累积 Δq),hpp 注释 "at reference + admittance offset joint angles" 说的就是这层物理含义。

力的通路:为什么绕道 world ​

传感器帧 → world → base,三座桥(base_ft_ / world_base_ / base_cog_):

  • 工具重量作为向量只有写在 world 里才是常量 [0,0,−mg](end_effector_weight_[2] = −CoG.force,:126);在 base 里方向随臂姿态变。
  • 力矩项 r×w:质心不在测点上时传感器多读一个重力力偶,r = cog_pos_ 参数经 R_world_cog 旋到 world(:189、:337)。
  • 命名规律:A_B_ = B 在 A 下的位姿;复合时下标相邻相消——R_world_base · R_base_sensor = R_world_sensor(:187 正是这行乘法)。

弹簧零点与两个场景 ​

X = 当前传感器位姿 − 参考传感器位姿(平移相减、旋转取 AngleAxis 对数,:261-265),输出 = 参考 + Δq(:214-223 叠加)。

  • 自由空间:F=0,偏移按二阶规律衰减到零,臂跟随上游轨迹——没被碰时必须还在轨道上。
  • 接触:稳态 K·X = F,弹簧压缩到与接触力平衡。注入 F_des 后(Humble 版没有这个参数,注入它的完整二次开发过程见本站《AdmittanceController 恒力控制二次开发踩坑记》)稳态变 K·X = F − F_des。

源码里的三处冗余(工业控制器视角的判断) ​

  1. base_tip_ 是死计算:全包 grep 只有 hpp:55 声明和 impl:155 写入,零读取,rule 也无 getter 把它递给控制器;git log -S 显示随首个 commit 9be3bfe2(2022-10-10,PR #370)进入至今无人消费。每周期为它付一次 FK。
  2. 每周期 7 次 FK、1 次重复:calculate_admittance_rule :260 重算当前构型传感器位姿,输入与 base_ft_ 完全相同(current_joint_pos 是 :199 从 current_joint_state.positions 拷的)。推测是为了让定律函数只依赖 AdmittanceState 自洽,重复计算是事实。
  3. world_base_ 对固定基座机器人(fixed_world_frame 与 base 刚连)物理上是常量,仍每周期重算。按工业控制器的标准,这两处都是可缓存项。

要点 ​

  • 六个位姿是把力、重力、M/D/K、弹簧零点搬进 base 帧的桥:只有 ref_base_ft_ 用参考关节角(弹簧零点需要「上游要你去哪」),其余五个全用当前关节角——力怎么旋转、重力怎么减、参数怎么换系只取决于臂的真实姿态。
  • 力的通路绕道 world:重量只有在 world 帧才是常向量 [0,0,−mg],先旋到 world 减重力再旋回 base;命名规律 A_B_ 复合时下标相邻相消。
  • 三处冗余(工业控制器视角):base_tip_ 自首个 commit 起零读取、每周期 7 次 FK 含 1 次重复、world_base_ 固定基座下物理上是常量——都是可缓存项。

控制器的生命周期、参数系统与实测排坑见本站《AdmittanceController 源码精读与全流程走查》;力控算法层面导纳与 PI 的定位对比,见本站《导纳控制与 PI 控制:力控算法的定位与对比》。

最近更新

基于 VitePress 构建